package com.example.net.oss

import android.content.Context
import android.util.Log
import com.alibaba.sdk.android.oss.*
import com.alibaba.sdk.android.oss.common.auth.OSSAuthCredentialsProvider
import com.alibaba.sdk.android.oss.exception.InconsistentException
import com.alibaba.sdk.android.oss.model.GetObjectRequest
import com.alibaba.sdk.android.oss.model.GetObjectResult
import com.alibaba.sdk.android.oss.model.OSSRequest
import java.io.IOException
import java.io.InputStream
import java.util.HashMap

/**
 * Author by lp,on 2020/12/24/024,14:11.
 */
class OssLoader(val context: Context) {
    private val TAG: String = "OssLoader"
    private var oss: OSS? = null
    private val SUCCESS = 0
    private val CLIENT_ERROR = -1
    private val SERVER_ERROR = -2
    private val BUCKET_NAME = "image-didanuo"

    init {
        oss = initOSS()
    }

    private fun initOSS(): OSS {
        //初始化
        Log.i(TAG, "initOSS..... ")
        val aliyun_oss_url = "/api/service/ossSts"
        val endpoint = "oss-cn-shenzhen.aliyuncs.com"
        val stsServer = "http://120.77.237.242:8081$aliyun_oss_url"
        //推荐使用OSSAuthCredentialsProvider。token过期可以及时更新
        val credentialProvider = OSSAuthCredentialsProvider(stsServer)
        //该配置类如果不设置，会有默认配置，具体可看该类
        val conf = ClientConfiguration()
        conf.connectionTimeout = 15 * 1000 // 连接超时，默认15秒
        conf.socketTimeout = 15 * 1000 // socket超时，默认15秒
        conf.maxConcurrentRequest = 5 // 最大并发请求数，默认5个
        conf.maxErrorRetry = 2 // 失败后最大重试次数，默认2次

        return OSSClient(context, endpoint, credentialProvider)
    }


    /**
     * 流式下载。即直接获取字节流
     * @param objectKey 指定文件要下载的文件路径，
     * @return
     */
    private fun streamDownload(objectKey: String, callback: StreamDownLoadCallback?): Int {
        if (callback == null) {
            throw NullPointerException("the StreamDownLoadCallback is null!")
        }
        oss?.let {
            Log.i(
                TAG,
                "threadId = " + Thread.currentThread().id + " stream download objectKey " + objectKey
            )
            //构造下载请求
            val get = GetObjectRequest(BUCKET_NAME, objectKey)
            //开启crc校验。保证下载的文件的数据完整性
            get.crC64 =
                OSSRequest.CRC64Config.YES//getObjectContent返回的InputStream是CheckCRC64DownloadInputStream,crc校验是在它的read函数中处理的
            /**
             * OSS通过在Get请求的Header中添加Accept-Encoding为gzip，对常见网页静态文件（HTML、Javascript、XML、json）内容进行gzip压缩，但必须满足以下条件：
             * 文件大小大于或者等于 1KB。
             * Conetnt-Type必须是 text/cache-manifest、text/xml、text/plain、text/css、application/javascript、application/x-javascript、application/rss+xml、application/json、text/json 中的一个。
             * 对静态文件，GET请求默认是会将Accept-Encoding设置为gzip的
             */
            val map = HashMap<String, String>()
            map["Accept-Encoding"] = ""
            get.requestHeaders = map
            var inputStream: InputStream? = null
            var result: GetObjectResult? = null
            try {
                // 同步执行下载请求，返回结果
                result = it.getObject(get)
                inputStream = result.objectContent
                callback.process(inputStream)
            } catch (e: InconsistentException) {
                e.printStackTrace()
                Log.i(TAG, "crc error -- > " + e.message)
                return CLIENT_ERROR
            } catch (e: ClientException) {
                e.printStackTrace()
                Log.i(TAG, "ClientException-->" + e.message)
                return CLIENT_ERROR
            } catch (e: ServiceException) {
                // 服务异常
                Log.i(TAG, "RequestId " + e.requestId)
                Log.i(TAG, "ErrorCode " + e.errorCode)
                Log.i(TAG, "HostId " + e.hostId)
                Log.i(TAG, "RawMessage " + e.rawMessage)
                Log.i(TAG, "ErrorCode " + e.errorCode)
                Log.i(TAG, "StatusCode " + "status code = " + e.statusCode)
                return SERVER_ERROR
            } catch (e: IOException) {
                e.printStackTrace()
                return CLIENT_ERROR
            } finally {
                if (result != null) {
                    val clientCrc = result.clientCRC!!
                    val serverCrc = result.serverCRC!!
                    Log.i(
                        TAG,
                        objectKey + " content-length : " + result.contentLength + " clientCrc = " + clientCrc + " serverCrc = " + serverCrc
                    )
                    Log.i(
                        TAG,
                        "content-length : " + result.metadata.contentLength + " clientCrc = " + clientCrc + " serverCrc = " + serverCrc
                    )
                }
                if (inputStream != null) {
                    try {
                        inputStream.close()
                    } catch (e: IOException) {
                        e.printStackTrace()
                        return CLIENT_ERROR
                    }

                }
            }
            return SUCCESS
        }
        return CLIENT_ERROR
    }

    /**
     * 直接获取流对象
     * @param objectKey
     * @param <T>
     * @return
    </T> */
    fun <T> streamDownloadObjectList(schooId: Int, cls: Class<Array<T>>): List<T>? {
        val objectKey = "syncthing/$schooId/student_face_features_v3"
        val callback = ObjectListStreamDownloadCallback<T>(cls)
        val reuslt = streamDownload(objectKey, callback)
        return callback.getObject()
    }
}